Part 1 of this pygtk tutorial stopped with a working toolbar and two place
holders. Part 2 of this tutorial extended this minimal UI with a list of
songs which was created using GTK ListView. Part 3 showed how to gain better control
on ListView
. Part 4 added some final polish to the UI and added an empty Preferences
Dialog. Part 5 of this tutorial added a gtk.Notebook
to the Preferences dialog, and
showed how to populate the first to Notebook pages (tabs) with the appropriate widget. Part 6
of the tutorial showed how to the gtk.Notebook, by populating the "Encode" and "Advanced"
pages, thus completing the Preferences dialog. This part of the tutorial will add more polish to the
UI. Here is how the UI looked when running the code after completing Part 6:
Here is what is missing from the UI:
The elements missing both contain an image, the rip button and the application logo, which is not visible in all GTK themes (the one in the photo is TradionalOK on Mate Desktop and Debian Wheezy).
The method responsible for loading the PNG image is window.set_icon_from_file(filename)
. Hence,
our window instance has already this method included, and it will be just add to the __init__
method of the main UI.
Before new code is introduced, I will take a short side deviation. In the previous parts of this
tutorial the code consisted of just one class, the PunderUI
class. However, keeping this
structure creates a very big class, which is getting harder and harder to maintain and follow.
Hence, I am going to separte some functionality from the main Window Class and put it in other classes.
This is not new, if you following the previous part of the tutorial, you have seen this done before
with the PrefDialog
class. Hence the structure the code will now be the following:
import gtk
class PrefDialog(object):
....
class AboutUI(object):
....
class PunderUI(object):
....
Back to adding the main Window icon, I add only one line:
def __init__(self):
"""
create the gui using GTK Window, and Toolbar.
"""
self.window = gtk.Window()
self.window.set_default_size(500, -1)
# Set VBox to heterogeneous so different widgets can have
# different sizes
# All widgets attached will be the same size
# Setting homogeneous to false makes the UI look sane
# only in a few cases we create VBOX with the homogenous option
vbox = gtk.VBox(False)
self.window.add(vbox)
...
...
# adding this line will add a window icon which will be propagated
# to all dialogs of the main program,
# try running the program and you will see this icon also added
# to the window of the Preferences dialog.
self.window.set_icon_from_file("asunder.png")
# add the elements needed to show the Rip Button:
self.make_rip_button(vbox)
self.window.show_all()
The next item, is the Rip button, to create this button I added a self baked
method to the init just below the calling of the built-in method set_icon_from_file
.
This method has all the usual elements that were show before and one extra new method.
The is the gtk.image_new_from_stock
method. GTK includes many more icons you can use
when needed:
def make_rip_button(self, vbox):
"""
add rip button, and icon to that button.
"""
# gtk.image_new_from_stock(stock_icon_name, size_in_pixels)
cdrom = gtk.image_new_from_stock(gtk.STOCK_CDROM, gtk.ICON_SIZE_BUTTON)
rip = gtk.Button()
label = gtk.Label("Rip")
fillerBox = gtk.HBox(False)
button_hbox = gtk.HBox(False)
button_hbox.pack_end(label, False, False)
button_hbox.pack_end(cdrom, False, False, 5)
rip.add(button_hbox)
fillerBox.pack_end(rip, False, False, 0)
vbox.pack_start(fillerBox, False, False, 0)
The method above is using all the usual tricks shown before. 3 GTK widgets are created (cdrom
,
rip
and label
). To these widgets 2 Boxes were added (filler_Box
and button_hbox
). The
boxes define the visual relationships between the widgets using packing as done many times before.
Finally, these elements are added to the main UI by packing them into vbox
which belongs to the
main window. The main window and the Preferences dialog are now completed. However the about dialog
is still not complete. The code for this dialog was included in the main UI class as a method and
gave some sparse information about the program:
def help_dialog(self, widget):
"""
create a GTK help dialog upon button click and destroy it when pressing the
close button
"""
self.about = gtk.AboutDialog()
sometext=gtk.Label('This is just the beggining.\nWill Get back to it later.')
self.about.vbox.pack_start(sometext)
self.about.show_all()
result = self.about.run()
# adding this will cause the about dialog to close when we
# press the button 'Close'.
self.about.hide()
However, a help dialog can contain much more info, and GTK includes many built in methods to supply the user with this info. Here is how to present this info, packed into a class:
class AboutUI(object):
"""
Show the about dialog
"""
def __init__(self, widget):
"""
create a GTK help dialog upon button click and destroy it when pressing the
close button
"""
self.about = gtk.AboutDialog()
sometext=gtk.Label('This is just the beggining.\nWill Get back to it later.')
#self.about.vbox.pack_start(sometext)
self.about.set_program_name("Punder")
self.about.set_comments("An application to save tracks from an Audio CD \n"+\
"as WAV, MP3, OGG, FLAC, Wavpack, Musepack, Monkey's Audio, and/or "+\
"AAC files.")
self.about.set_license("This program is distributed under the terms of GPLv3+.")
self.about.set_copyright("Copyright 2013 Oz Nahum")
self.about.set_website("https://github.com/oz123/punder")
authors = ["Oz Nahum"]
self.about.set_authors(authors)
self.about.set_translator_credits("German - Franz Schubert\nFrench - Leon Blum")
self.about.set_artists(["The CD icon of Punder is originally from Asunder.\nhttp://littlesvr.ca/asunder/"])
self.about.show_all()
self.about.set_icon_from_file("asunder.png")
self.about.run()
# adding this will cause the about dialog to close when we
# press the button 'Close'.
self.about.hide()
This class contains much more info, comparing to the previous method. The main PunderUI needs to know
how to use this class. Previously, the About
button was connected to a method:
button_about.connect("clicked", self.help_dialog)
However, the help_dialop
does not exist anymore, and instead the button is connected to calling an
instance of the AboutUI class in the following way:
button_about.connect("clicked", AboutUI)
With this last addition, the UI is complete (as usual, the full code is here):
Further work on this application will be to get it working. Hence this will be infrastructure code, no Screenshots to share. If you like this tutorial, you can keep following the changes by staring it on github, or visiting this blog again.
Share this post: